"""Automatically generate handle documentation files.

This script:
1. Imports viser and inspects all exported classes.
2. Categorizes them by module (GUI handles vs Scene handles).
3. Generates RST files with appropriate autoclass directives.
4. Sorts classes alphabetically for consistent output.
"""

import inspect
from pathlib import Path
from typing import Dict, List

import viser


def get_handle_classes() -> Dict[str, List[str]]:
    """Get all handle classes from viser, categorized by name and module."""
    events = []
    gui_handles = []
    scene_handles = []

    # Get all exported items from viser
    for name in sorted(dir(viser)):
        obj = getattr(viser, name)

        # Skip non-classes and private items
        if not inspect.isclass(obj) or name.startswith("_"):
            continue

        # Categorize by name first, then by module
        module = getattr(obj, "__module__", "")
        if "Event" in name:
            events.append(name)
        elif module == "viser._gui_handles":
            gui_handles.append(name)
        elif module == "viser._scene_handles":
            scene_handles.append(name)

    return {"events": events, "gui": gui_handles, "scene": scene_handles}


def generate_gui_handles_rst(handles: List[str]) -> str:
    """Generate the GUI handles RST file content."""
    content = """.. This file is automatically generated by generate_handle_docs.py
.. Do not edit manually - run the script to regenerate

GUI Handles
===========

"""

    for handle in handles:
        content += f".. autoclass:: viser.{handle}\n\n"

    return content


def generate_events_rst(events: List[str]) -> str:
    """Generate the events RST file content."""
    content = """.. This file is automatically generated by generate_handle_docs.py
.. Do not edit manually - run the script to regenerate

Events
======

We define a small set of event types, which are passed to callback functions
when events like clicks or GUI updates are triggered.

"""

    for event in events:
        content += f".. autoclass:: viser.{event}()\n\n"

    return content


def generate_scene_handles_rst(handles: List[str]) -> str:
    """Generate the scene handles RST file content."""
    content = """.. This file is automatically generated by generate_handle_docs.py
.. Do not edit manually - run the script to regenerate

Scene Handles
=============

A handle is created for each object that is added to the scene. These can be
used to read and set state, as well as detect clicks.

When a scene node is added to a server (for example, via
:func:`viser.ViserServer.add_frame()`), state is synchronized between all
connected clients. When a scene node is added to a client (for example, via
:func:`viser.ClientHandle.add_frame()`), state is local to a specific client.

The most common attributes to read and write here are
:attr:`viser.SceneNodeHandle.wxyz` and :attr:`viser.SceneNodeHandle.position`.
Each node type also has type-specific attributes that we can read and write.
Many of these are lower-level than their equivalent arguments in factory
methods like :func:`viser.ViserServer.add_frame()` or
:func:`viser.ViserServer.add_image()`.

"""

    for handle in handles:
        content += f".. autoclass:: viser.{handle}\n\n"

    return content


def main():
    """Generate handle documentation files."""
    # Get the docs directory
    docs_dir = Path(__file__).parent
    handles_dir = docs_dir / "source" / "api" / "handles"
    advanced_dir = docs_dir / "source" / "api" / "advanced"

    # Get handle classes
    handle_classes = get_handle_classes()

    # Generate events file
    events_content = generate_events_rst(handle_classes["events"])
    events_path = advanced_dir / "events.rst"

    print(f"Writing {len(handle_classes['events'])} events to {events_path}")
    with open(events_path, "w") as f:
        f.write(events_content)

    # Generate GUI handles file
    gui_content = generate_gui_handles_rst(handle_classes["gui"])
    gui_path = handles_dir / "gui_handles.rst"

    print(f"Writing {len(handle_classes['gui'])} GUI handles to {gui_path}")
    with open(gui_path, "w") as f:
        f.write(gui_content)

    # Generate scene handles file
    scene_content = generate_scene_handles_rst(handle_classes["scene"])
    scene_path = handles_dir / "scene_handles.rst"

    print(f"Writing {len(handle_classes['scene'])} scene handles to {scene_path}")
    with open(scene_path, "w") as f:
        f.write(scene_content)

    print("Handle documentation files updated successfully!")
    print("\nEvents found:")
    for event in handle_classes["events"]:
        print(f"  - {event}")

    print("\nGUI handles found:")
    for handle in handle_classes["gui"]:
        print(f"  - {handle}")

    print("\nScene handles found:")
    for handle in handle_classes["scene"]:
        print(f"  - {handle}")


if __name__ == "__main__":
    main()
